using System;
using System.Collections.Generic;
using Gj.Galaxy.Logic;
using MessagePack;
using SimpleJSON;
using UnityEngine;

namespace Gj.MapData
{
    public class DefineBase
    {
        public const string Position = "position";
        public static FieldsDefineManager FDM = new();
        public static int ConvertArrayToInt(int[] enumArray)
        {
            int result = 0;
            for (int i = 0; i < enumArray.Length; i++)
            {
                // 每个值左移i位，然后通过按位或（|）合并
                result |= ((int)enumArray[i] << i);
            }
            return result;
        }

        public static int[] ConvertToIntArray(object data)
        {
            if (data == null) return new int[0];
            var objs = (object[])data;
            var list = new int[objs.Length];
            for (var i = 0; i < objs.Length; i++)
            {
                list[i] = Convert.ToInt32(objs[i]);
            }
            return list;
        }
    }

    public enum MapMode : byte
    {
        Square,
        RowHex,
        ColumnHex
    }

    public enum EventMode : byte
    {
        Node,
        Operate,
        Task,
        Schedule,
        Event
    }

    public enum Operate : byte
    {
        None,
        Create,
        BatchUpdate,
        Delete,
        Reset,
        Event
    }

    public enum UpdateOperate : byte
    {
        ChangeData,
        ChangeDataSync,
        ChangeDateTime,
        ChangePosition,
        ChangeIgnore,
        ChangeInherit,
        ChangeDataGreater,
        ChangeDataLesser,
        ChangeDataGreaterSync,
        ChangeDataLesserSync,
        IncrData,
        IncrDataSync,
        IncrDataGreater,
        IncrDataLesser,
        IncrDataGreaterSync,
        IncrDataLesserSync,
        ChangeList,
        ChangeListTime,
        IncrList,
        IncrListFrom,
        AddSet,
        RemoveSet,
        ResetSet,
        AddSorted,
        RemoveSorted,
        ResetSorted,
        AddTimeSorted,
        RemoveTimeSorted,
        ClearTimeSorted,
        ResetTimeSorted,

        PushSchedule,
        ResetSchedule,
        RemoveSchedule,
        ChangeParamSchedule,
        HoldSchedule,

        BindEvent,

        // LinkEvent,
        ClearEvent,
        // UnLinkEvent,

        AddTask,

        // UpdateNode,
        // UpdateFixed,
        // UpdateSeat,

        AddDepend,
        RemoveDepend,
        AddRelation,
        RemoveRelation,
        AddLink,
        RemoveLink,
        AddToLink,
        RemoveFromLink
    }

    public enum CheckType : byte
    {
        None,
        Exist,
        NoExist,
        PositionEqual,
        PositionUnEqual,
        Data,
        Equal,
        Greater,
        Less,
        ListEqual,
        ListGreater,
        ListLess,
        SetExist,
        SetNoExist,
        SortedExist,
        SortedNoExist,
        SortedGreater,
        SortedLess,
        SustainTimeExist,
        SustainTimeNoExist
    }

    public enum ScheduleLogic : byte
    {
        None,
        Once,
        Repeat,
        RepeatEvery,
        Move,
        Touch,
        Query,
        SelfProcess,
        Custom
    }

    public class DefineBaseType
    {
        public static void Parse(DuplexData data, byte[] content)
        {
            var objects = MessagePackSerializer.Deserialize<object[]>(content);
            data.Parse(objects);
        }
    }

    public interface DefineData : SubmitData
    {
        DataType GetDataType();
        object GetId();
        FieldsDefine GetFieldDefine();
    }

    public interface SubmitData
    {
        object Object();
    }

    public interface DuplexData : SubmitData
    {
        void Parse(object[] data);
    }

    public interface SubmitKeyData : SubmitData
    {
        string[] Keys();
    }

    public class TaskDemo : DuplexData
    {
        public object Object()
        {
            return null;
        }

        public void Parse(object[] data)
        {
        }
    }

    public class TypeEnumExtend
    {
        public byte _value;

        public TypeEnumExtend(int v)
        {
            _value = (byte)v;
        }

        public TypeEnumExtend(byte v)
        {
            _value = v;
        }

        public byte Value()
        {
            return _value;
        }

        public override bool Equals(object obj)
        {
            var a = obj as TypeEnumExtend;
            if (a == null) return false;
            return Equals(a);
        }

        protected bool Equals(TypeEnumExtend other)
        {
            return _value == other._value;
        }

        public override int GetHashCode()
        {
            return _value.GetHashCode();
        }
    }

    public class DataType : TypeEnumExtend
    {
        public DataType(byte v) : base(v)
        {
        }
    }

    public class SystemEvent : TypeEnumExtend
    {
        public SystemEvent(byte v) : base(v)
        {
        }
    }

    public class LogicType
    {
        public byte _value;

        public LogicType(byte v)
        {
            _value = v;
        }

        public byte Value()
        {
            return _value;
        }
    }

    public class PositionInt
    {
        public int X;
        public int Y;

        public static PositionInt FromVector(Vector2Int position)
        {
            return new PositionInt { X = position.x, Y = position.y };
        }

        public Vector2Int ToVector2Int()
        {
            return new Vector2Int { x = X, y = Y };
        }

        public bool Equals(PositionInt position)
        {
            if (position == null) return false;
            if (position.X != X) return false;
            if (position.Y != Y) return false;
            return true;
        }

        public static PositionInt Parse(byte[] data)
        {
            if (data == null) return null;
            if (data.Length == 0) return null;
            var v = SerializeInt.Byte2Vector(data);
            var p = new PositionInt { X = v.x, Y = v.y };
            return p;
        }

        public static byte[] Object(PositionInt position)
        {
            if (position == null) return new byte[0];
            return SerializeInt.Int2Byte(position.X, position.Y);
        }

        public static PositionInt[] Parse(object[] obj)
        {
            var list = new PositionInt[obj.Length];
            for (var i = 0; i < obj.Length; i++) list[i] = Parse((byte[])obj[i]);
            return list;
        }
    }

    public class DefineNodeData
    {
        public int DataType;
        public string Key = "";
        public PositionInt Position;

        public JSONObject Object()
        {
            var data = new JSONObject();
            data.Add("dataType", DataType);
            data.Add("key", Key);
            data.Add("position", Position.X + "," + Position.Y);
            return data;
        }

        public static object[] Array(ShowDataNode[] list)
        {
            if (list == null) return new object[] { };
            var s = new object[list.Length];
            for (var i = 0; i < s.Length; i++) s[i] = list[i].Object();

            return s;
        }
    }

    public class ShowDataNode
    {
        public int DataType;
        public string Id = "";
        public string Name = "";
        public PositionInt Position;

        public object Object()
        {
            return new object[] { Id ?? "", DataType, Name ?? "", PositionInt.Object(Position) };
        }

        public static object[] Array(ShowDataNode[] list)
        {
            if (list == null) return new object[] { };
            var s = new object[list.Length];
            for (var i = 0; i < s.Length; i++) s[i] = list[i].Object();

            return s;
        }
    }

    public class InlineDataNode
    {
        public int DataType;
        public string Id;
        public int Identity;
        public Dictionary<string, object> Params;

        public PositionInt Position;

        public object Object()
        {
            return new object[]
            {
                Id ?? "", Identity, DataType, PositionInt.Object(Position), Params ?? new Dictionary<string, object>()
            };
        }

        public static object[] Array(InlineDataNode[] list)
        {
            if (list == null) return new object[] { };
            var s = new object[list.Length];
            for (var i = 0; i < s.Length; i++) s[i] = list[i].Object();

            return s;
        }
    }

    public class DataNode
    {
        public PositionInt Position;
        public byte Type;

        public object Object()
        {
            return new object[] { PositionInt.Object(Position), Type };
        }

        public static object[] Array(DataNode[] list)
        {
            if (list == null) return new object[] { };
            var s = new object[list.Length];
            for (var i = 0; i < s.Length; i++) s[i] = list[i].Object();

            return s;
        }
    }

    public class DataDefineNode
    {
        public int Identity = 0;

        // 服务端Key必须填写
        public string Key = "";
        public Vector2Int Position;

        public object Object()
        {
            return new object[] { SerializeInt.Vector2Byte(Position), Key, Identity };
        }

        public static object[] Array(DataDefineNode[] list)
        {
            if (list == null) return new object[] { };
            var s = new object[list.Length];
            for (var i = 0; i < s.Length; i++) s[i] = list[i].Object();

            return s;
        }
    }

    public class RangeDefineNode
    {
        public Vector2Int Position;
        public Vector2Int[] Range;

        public object Object()
        {
            return new object[] { SerializeInt.Vector2Byte(Position), SerializeInt.Vector2Byte(Range) };
        }

        public static object[] Array(RangeDefineNode[] list)
        {
            if (list == null) return new object[] { };
            var s = new object[list.Length];
            for (var i = 0; i < s.Length; i++) s[i] = list[i].Object();

            return s;
        }
    }

    public class MapNode
    {
        public string MapNoId;
        public Vector2Int Position;

        public MapNode(object[] objs)
        {
            MapNoId = Convert.ToString(objs[0]);
            Position = SerializeInt.Byte2Vector((byte[])objs[1]);
        }

        public MapNode(string mapNoId, Vector2Int position)
        {
            MapNoId = mapNoId;
            Position = position;
        }
    }


    public class FieldDefine
    {
        public byte ChessIndex;
        public byte NoticeIndex;
        public string Prop;
        public string PropType;
    }

    public interface DefineFieldInf
    {
        void DefineField(FieldsDefine fd);
    }

    public class BeDependDefine
    {
        public string BeDepend;
        public bool BeDependIsPosition;
        public DataType BeDependType;
        public string Depend;
        public bool DependIsPosition;
        public DataType DependType;
        public int Index;
        public bool IsChess;
    }

    public class DependDefine
    {
        public BeDependDefine Be;
        public bool IsPosition;
        public string Key;
    }

    public class FieldsDefineManager
    {
        public List<string> Chess = new();
        public List<string> Notice = new();

        public FieldsDefineManager BindNotice(params string[] fields)
        {
            Notice.AddRange(fields);
            return this;
        }

        public FieldsDefineManager BindChess(params string[] fields)
        {
            Chess.AddRange(fields);
            return this;
        }

        public FieldsDefineManager Finish(FieldsDefine fd)
        {
            foreach (var key in Notice)
                if (fd.NoticeOther.Contains(key))
                    fd.BindNotice(key);
            foreach (var key in Chess)
                if (fd.ChessOther.Contains(key))
                    fd.BindChess(key);
            return this;
        }
    }


    public class FieldsDefine
    {
        public static Dictionary<byte, FieldsDefine> FDMap;
        public static string PositionProp;


        private string _propType;
        public Dictionary<string, int> BeDependMap = new();
        public List<BeDependDefine> BeDepends = new();
        public List<string> ChessExtend = new();
        public List<string> ChessOther = new();
        public List<string> ChessProp = new();
        public string DataKey;
        public DataType DataType;

        public Dictionary<string, DependDefine> DependMap = new();
        public bool IsChess;
        public bool IsManage;
        public bool IsPosition;

        public Dictionary<string, FieldDefine> Map = new();
        public List<string> NoticeExtend = new();
        public List<string> NoticeOther = new();
        public List<string> NoticeProp = new();

        public FieldsDefine(DataType dataType, string key)
        {
            DataType = dataType;
            DataKey = key;
        }

        public void Init(Dictionary<byte, FieldsDefine> fdMap)
        {
            foreach (var beDepend in BeDepends)
            {
                beDepend.BeDependIsPosition = IsPosition;
                if (!fdMap.ContainsKey(beDepend.DependType.Value())) continue;
                var fd = fdMap[beDepend.DependType.Value()];
                beDepend.DependIsPosition = fd.IsPosition;
            }

            foreach (var fdfd in fdMap)
                foreach (var beDepend in fdfd.Value.BeDepends)
                    if (beDepend.DependType.Value() == DataType.Value())
                        DependMap[beDepend.Depend] = new DependDefine
                        {
                            Key = beDepend.Depend,
                            Be = beDepend,
                            IsPosition = fdfd.Value.IsPosition
                        };
        }

        public FieldsDefine SetPosition(bool isPosition)
        {
            IsPosition = isPosition;
            return this;
        }

        public FieldsDefine SetChess(bool isChess)
        {
            IsChess = isChess;
            return this;
        }

        public FieldsDefine SetManage(bool isManage)
        {
            IsManage = isManage;
            return this;
        }

        public FieldsDefine BindBeDepend(string beDependKey, DataType dataType, string dependKey, bool isChess)
        {
            if (BeDependMap.ContainsKey(beDependKey)) return this;

            BeDependMap[beDependKey] = BeDepends.Count;
            BeDepends.Add(new BeDependDefine
            {
                Index = BeDependMap[beDependKey],
                BeDepend = beDependKey,
                BeDependType = DataType,
                Depend = dependKey,
                DependType = dataType,
                IsChess = isChess
            });
            return this;
        }

        public FieldsDefine Bind(string propType, DefineFieldInf inf)
        {
            _propType = propType;
            inf.DefineField(this);
            return this;
        }

        public FieldsDefine BindNotice(params string[] fields)
        {
            for (var i = 0; i < fields.Length; i++)
            {
                var prop = fields[i];
                if (!Map.ContainsKey(prop))
                    Map.Add(prop,
                        new FieldDefine { Prop = prop, PropType = _propType, NoticeIndex = (byte)NoticeProp.Count });
                else
                    Map[prop].NoticeIndex = (byte)NoticeProp.Count;
                NoticeProp.Add(prop);
            }

            return this;
        }

        public FieldsDefine BindNoticeOther(params string[] fields)
        {
            NoticeOther.AddRange(fields);
            return this;
        }

        public FieldsDefine BindNoticeExtend(params string[] extendFields)
        {
            for (var i = 0; i < extendFields.Length; i++)
            {
                var prop = extendFields[i];
                if (!Map.ContainsKey(prop)) Map.Add(prop, new FieldDefine { Prop = prop, PropType = _propType });
                NoticeExtend.Add(prop);
            }

            return this;
        }

        public FieldsDefine BindChess(params string[] fields)
        {
            for (var i = 0; i < fields.Length; i++)
            {
                var prop = fields[i];
                if (!Map.ContainsKey(prop))
                    Map.Add(prop,
                        new FieldDefine { Prop = prop, PropType = _propType, ChessIndex = (byte)ChessProp.Count });
                else
                    Map[prop].ChessIndex = (byte)ChessProp.Count;
                ChessProp.Add(prop);
            }

            return this;
        }

        public FieldsDefine BindChessOther(params string[] fields)
        {
            ChessOther.AddRange(fields);
            return this;
        }

        public FieldsDefine BindChessExtend(params string[] extendFields)
        {
            for (var i = 0; i < extendFields.Length; i++)
            {
                var prop = extendFields[i];
                if (!Map.ContainsKey(prop)) Map.Add(prop, new FieldDefine { Prop = prop, PropType = _propType });
                ChessExtend.Add(prop);
            }

            return this;
        }

        public FieldsDefine Finish()
        {
            DefineBase.FDM.Finish(this);
            return this;
        }

        public UpdateResult CreateRender(DataInfo dataInfo, ChessData data)
        {
            var result = dataInfo.GetResult();
            result.Clear();
            // 手动更新坐标
            var mapProp = dataInfo.Receive(PositionProp);
            object oldPosition;
            mapProp.UpdateField(DefineBase.Position, SerializeInt.Vector2Byte(data.Position), out oldPosition);

            for (var i = 0; i < data.Props.Length; i++)
            {
                var value = data.Props[i];
                if (ChessProp.Count <= i) continue;
                var field = ChessProp[i];
                var fp = Map[field];
                var updateInstance = dataInfo.Receive(fp.PropType);
                // Debug.LogError(fp.Prop + ":" + fp.PropType + ":" + field + ":" + updateInstance + ":" + value);
                object old;
                if (updateInstance.UpdateField(fp.Prop, value, out old)) result.AddField(fp.Prop, old);
            }

            for (var i = 0; i < data.Extends.Length; i++)
            {
                var list = data.Extends[i];
                if (ChessExtend.Count <= i) continue;
                var field = ChessExtend[i];
                var fp = Map[field];
                var updateInstance = dataInfo.Receive(fp.PropType);
                // Debug.LogErrorFormat("extend {0} => [{1}] {2}", i, field, list);
                updateInstance.UpdateExtend(field, new UpdateExtendTotal { Reset = list }, result);
                result.AddExtend(field);
            }

            // todo
            if (data.ListId != null)
            {
            }

            if (data.ListNo != null)
            {
            }

            if (data.ListNode != null)
            {
            }

            if (data.Message != null && data.Message.Persistent) dataInfo.SetMessage(data.Message);

            return result;
        }

        public UpdateResult UpdateRender(DataInfo dataInfo, UpdatePublicData data)
        {
            var result = dataInfo.GetResult();
            result.Clear();
            if (data == null || !data.IsExist) return result;
            for (var i = 0; i < data.Props.Length; i++)
            {
                var value = data.Props[i];
                if (ChessProp.Count <= value.Key) continue;
                var field = ChessProp[value.Key];
                var fp = Map[field];
                var updateInstance = dataInfo.Receive(fp.PropType);
                object old;
                if (updateInstance.UpdateField(fp.Prop, value.Value, out old)) result.AddField(fp.Prop, old);
            }

            var mt = data.ParseExtend();
            var fd = FDMap[dataInfo.GetDataType().Value()];

            if (mt != null)
            {
                var e = mt.GetEnumerator();
                while (e.MoveNext())
                {
                    var c = e.Current;
                    if (ChessExtend.Count <= c.Key) continue;
                    var field = ChessExtend[c.Key];
                    var fp = Map[field];
                    var updateInstance = dataInfo.Receive(fp.PropType);
                    updateInstance.UpdateExtend(field, c.Value, result);
                    if (c.Value.Reset != null)
                        result.AddExtend(field);
                    else
                        foreach (var ue in c.Value.List)
                            result.AddExtend(field, ue.Index);
                }

                e.Dispose();
            }

            if (data.ListId != null)
                foreach (var beDependent in data.ListId)
                {
                    if (fd.BeDepends.Count <= beDependent.Key) continue;
                    var depend = fd.BeDepends[beDependent.Key];
                    var list = dataInfo.ListId(depend);
                    if (list == null) continue;
                    if (beDependent.Logic)
                        list.Add(beDependent.Value);
                    else
                        list.Remove(beDependent.Value);
                    result.DependId.Add((byte)beDependent.Key);
                }

            if (data.ListNo != null)
                foreach (var beDependent in data.ListNo)
                {
                    if (fd.BeDepends.Count <= beDependent.Key) continue;
                    var depend = fd.BeDepends[beDependent.Key];
                    var list = dataInfo.ListNo(depend);
                    if (list == null) continue;
                    if (beDependent.Logic)
                        list.Add(beDependent.Value);
                    else
                        list.Remove(beDependent.Value);
                    result.DependNo.Add((byte)beDependent.Key);
                }

            if (data.ListNode != null)
                foreach (var ownNode in data.ListNode)
                {
                    if (fd.BeDepends.Count <= ownNode.Key) continue;
                    var depend = fd.BeDepends[ownNode.Key];
                    var list = dataInfo.ListNode(depend);
                    if (list == null) continue;
                    if (ownNode.Logic) list.Add(new MapNode("", SerializeInt.Byte2Vector(ownNode.Value)));
                    result.DependNode.Add((byte)ownNode.Key);
                }

            if (data.Message != null && data.Message.Persistent) dataInfo.SetMessage(data.Message);

            return result;
        }

        public UpdateResult UpdateNotice(DataInfo dataInfo, UpdatePublicData data)
        {
            var result = dataInfo.GetResult();
            result.Clear();
            if (data == null || !data.IsExist) return result;
            for (var i = 0; i < data.Props.Length; i++)
            {
                var value = data.Props[i];
                if (NoticeProp.Count <= value.Key) continue;
                var field = NoticeProp[value.Key];
                var fp = Map[field];
                var updateInstance = dataInfo.Receive(fp.PropType);
                object old;
                if (updateInstance.UpdateField(fp.Prop, value.Value, out old)) result.AddField(fp.Prop, old);
            }

            var mt = data.ParseExtend();
            var fd = FDMap[dataInfo.GetDataType().Value()];

            if (mt != null)
            {
                var e = mt.GetEnumerator();
                while (e.MoveNext())
                {
                    var c = e.Current;
                    if (NoticeExtend.Count <= c.Key) continue;
                    var field = NoticeExtend[c.Key];
                    var fp = Map[field];
                    var updateInstance = dataInfo.Receive(fp.PropType);
                    updateInstance.UpdateExtend(field, c.Value, result);
                    if (c.Value.Reset != null)
                        result.AddExtend(field);
                    else
                        foreach (var ue in c.Value.List)
                            result.AddExtend(field, ue.Index);
                }

                e.Dispose();
            }

            if (data.ListId != null)
                foreach (var beDependent in data.ListId)
                {
                    if (fd.BeDepends.Count <= beDependent.Key) continue;
                    var depend = fd.BeDepends[beDependent.Key];
                    var list = dataInfo.ListId(depend);
                    if (list == null) continue;
                    if (beDependent.Logic)
                        list.Add(beDependent.Value);
                    else
                        list.Remove(beDependent.Value);
                    result.DependId.Add((byte)beDependent.Key);
                }

            if (data.ListNo != null)
                foreach (var beDependent in data.ListNo)
                {
                    if (fd.BeDepends.Count <= beDependent.Key) continue;
                    var depend = fd.BeDepends[beDependent.Key];
                    var list = dataInfo.ListNo(depend);
                    if (list == null) continue;
                    if (beDependent.Logic)
                        list.Add(beDependent.Value);
                    else
                        list.Remove(beDependent.Value);
                    result.DependNo.Add((byte)beDependent.Key);
                }

            if (data.ListNode != null)
                foreach (var ownNode in data.ListNode)
                {
                    if (fd.BeDepends.Count <= ownNode.Key) continue;
                    var depend = fd.BeDepends[ownNode.Key];
                    var list = dataInfo.ListNode(depend);
                    if (list == null) continue;
                    if (ownNode.Logic) list.Add(new MapNode("", SerializeInt.Byte2Vector(ownNode.Value)));
                    result.DependNode.Add((byte)ownNode.Key);
                }

            if (data.Message != null && data.Message.Persistent) dataInfo.SetMessage(data.Message);

            return result;
        }
    }

    public interface BaseProp
    {
        object GetField(string key);
    }

    public interface UpdateProp : BaseProp
    {
        bool UpdateField(string key, object value, out object old);
        void UpdateExtend(string extend, UpdateExtendTotal total, UpdateResult result);
    }

    public interface PropDefineData : DefineData, UpdateProp
    {
        DefineData[] Inherits();
        UpdateProp Receive(string propType);
    }

    public interface DataInfo : PropDefineData
    {
        UpdateResult GetResult();
        void SetMessage(EventMessage message);
        List<string> ListId(BeDependDefine be);
        List<int> ListNo(BeDependDefine be);
        List<MapNode> ListNode(BeDependDefine be);
    }

    public static class TimeTools
    {
        public static long FormatTime(float delaySecond)
        {
            return (long)(delaySecond * 1000);
        }

        public static int FormatSecond(float delaySecond)
        {
            return (int)delaySecond;
        }

        public static long CurrentSecond()
        {
            return new DateTimeOffset(DateTime.UtcNow).ToUnixTimeSeconds();
        }

        public static long CurrentMill()
        {
            return new DateTimeOffset(DateTime.UtcNow).ToUnixTimeMilliseconds();
        }
    }

    public class BaseData : DefineData, SubmitData
    {
        public DataType DataType;
        public object Id;

        public DataType GetDataType()
        {
            return DataType;
        }

        public object GetId()
        {
            return Id;
        }

        public FieldsDefine GetFieldDefine()
        {
            throw new NotImplementedException();
        }

        public object Object()
        {
            return new[] { (int)(DataType?.Value() ?? 0), Id is Vector2Int ? SerializeInt.Vector2Byte((Vector2Int)Id) : Id };
        }

        public static BaseData Parse(DataType dataType, object id)
        {
            var b = new BaseData();
            b.DataType = dataType;
            b.Id = id;
            return b;
        }

        public static BaseData Get(object[] data)
        {
            var b = new BaseData();
            b.DataType = new DataType(Convert.ToByte(data[0]));
            b.Id = data[1];
            return b;
        }

        public static BaseData From(DefineData defineData)
        {
            var b = new BaseData();
            b.DataType = defineData.GetDataType();
            b.Id = defineData.GetId();
            return b;
        }

        public byte[] Bytes()
        {
            var tmp = Id;
            Id = Convert.ToString(tmp);
            var n = MessagePackSerializer.Serialize(Object());
            Id = tmp;
            return n;
        }

        public static object Array(BaseData[] baseDataList)
        {
            if (baseDataList == null) return new object[0];
            var objs = new object[baseDataList.Length];
            for (var i = 0; i < baseDataList.Length; i++) objs[i] = baseDataList[i].Object();

            return objs;
        }

        public int GetIntId()
        {
            return Convert.ToInt32(Id);
        }

        public bool Equals(object obj)
        {
            var data = obj as DefineData;
            if (data == null) return false;
            if (!GetDataType().Equals(data.GetDataType())) return false;
            return data.GetId().Equals(GetId());
        }
    }

    public class Sustain
    {
        public bool CanBreak;
        public object[] Params;
        public string Schedule;
        public long Start;
        public long Time;
        public int Type;

        public Sustain(object[] data)
        {
            Type = Convert.ToInt32(data[0]);
            if (data[1] != null)
                Params = (object[])data[1];

            Start = Convert.ToInt64(data[2]);
            Time = Convert.ToInt64(data[3]);
            CanBreak = Convert.ToBoolean(data[4]);
            Schedule = Convert.ToString(data[5]);
        }

        public Sustain()
        {
        }

        public int SurplusTime()
        {
            return (int)(Time / 1000) - (int)TimeTools.CurrentSecond();
        }

        public int AllTime()
        {
            return (int)((Time - Start) / 1000);
        }

        public object[] Object()
        {
            return new object[] { Type, Params, Start, Time, CanBreak, string.IsNullOrEmpty(Schedule) ? "" : Schedule };
        }
    }

    public class SustainSingle
    {
        public int BreakAction;
        public int CanAction;
        public object[] Params;
        public long Start;
        public long Time;
        public int Type;

        public SustainSingle(object[] data)
        {
            Type = Convert.ToInt32(data[0]);
            if (data[1] != null)
                Params = (object[])data[1];
            Start = Convert.ToInt64(data[2]);
            Time = Convert.ToInt64(data[3]);
            CanAction = Convert.ToInt32(data[4]);
            BreakAction = Convert.ToInt32(data[5]);
        }

        public SustainSingle()
        {
        }

        public int SurplusTime()
        {
            return (int)(Time / 1000) - (int)TimeTools.CurrentSecond();
        }

        public int AllTime()
        {
            return (int)((Time - Start) / 1000);
        }

        public object[] Object()
        {
            return new object[] { Type, Params, Start, Time, CanAction, BreakAction };
        }
    }

    public class Transmit
    {
        public int TriggerAction;
        public bool CanCover;
        public object[] Params;
        public float Start;
        public float Time;
        public int Type;
        public int DirectId;

        public Transmit(object[] data)
        {
            Type = Convert.ToInt32(data[0]);
            if (data[1] != null)
                Params = (object[])data[1];
            Start = Convert.ToInt64(data[2]);
            Time = Convert.ToInt64(data[3]);
            TriggerAction = Convert.ToInt32(data[4]);
            CanCover = Convert.ToBoolean(data[5]);
        }

        public Transmit()
        {
        }

        public int SurplusTime()
        {
            return (int)(Time) - (int)TimeTools.CurrentSecond();
        }

        public int AllTime()
        {
            return (int)((Time - Start));
        }

        public object[] Object()
        {
            return new object[] { Type, Params, Start, Time, TriggerAction, CanCover };
        }
    }
    public class MapPath : SubmitData
    {
        public Vector2Int Block;
        public List<Vector2Int> Boundary;
        public Vector2Int Center;
        public DataNode[] DataNodes;
        public MapMode Mode;
        public Vector2Int Size;


        public object Object()
        {
            return new object[]
            {
                SerializeInt.Vector2Byte(Size), SerializeInt.Vector2Byte(Center), SerializeInt.Vector2Byte(Block),
                (byte)Mode, DataNode.Array(DataNodes), SerializeInt.Vector2Byte(Boundary?.ToArray())
            };
        }
    }

    public class MapInit : SubmitData
    {
        public SubmitData Extend;
        public List<InlineDataNode> Inlines;
        public List<ShowDataNode> Shows;

        public object Object()
        {
            return new object[]
            {
                ShowDataNode.Array(Shows?.ToArray()), InlineDataNode.Array(Inlines?.ToArray()),
                Extend != null ? MessagePackSerializer.Serialize(Extend.Object()) : new byte[] { }
            };
        }
    }

    public class MapDefine
    {
        public List<DefineNodeData> Nodes;

        public JSONObject Object()
        {
            var data = new JSONObject();
            var nodes = new JSONArray();
            if (Nodes != null) foreach (var node in Nodes) nodes.Add(node.Object());
            data.Add("nodes", nodes);
            return data;
        }
    }

    public class MapPosition : SubmitData
    {
        public string Id;
        public string Name;
        public Vector2Int Position;

        public object Object()
        {
            return new object[] { Id, Name ?? "", SerializeInt.Vector2Byte(Position) };
        }

        public static object[] Array(MapPosition[] list)
        {
            if (list == null) return new object[] { };
            var s = new object[list.Length];
            for (var i = 0; i < s.Length; i++) s[i] = list[i].Object();

            return s;
        }
    }

    //TODO 缓存池
    public class UpdateResult
    {
        public Dictionary<string, List<byte>> ChangeExtend = new();
        public Dictionary<string, object> OldFields = new();
        public Dictionary<string, object> NewFields = new();
        public List<byte> DependId = new();
        public List<byte> DependNo = new();
        public List<byte> DependNode = new();

        public void AddField(string field, object oldf)
        {
            var r = OldFields.TryAdd(field, oldf);
            // Debug.LogError("add field:" + field + "=>" + old + " : " + r);
        }

        public void SaveField(string field, object newf)
        {
            var r = NewFields.TryAdd(field, newf);
        }

        public void AddExtend(string extend, byte index)
        {
            List<byte> indexs;
            if (!ChangeExtend.TryGetValue(extend, out indexs))
            {
                indexs = new List<byte>();
                ChangeExtend.Add(extend, indexs);
            }

            indexs.Add(index);
        }

        public void AddExtend(string extend, byte[] index)
        {
            List<byte> indexs;
            if (!ChangeExtend.TryGetValue(extend, out indexs))
            {
                indexs = new List<byte>();
                ChangeExtend.Add(extend, indexs);
            }

            indexs.AddRange(index);
        }

        public void AddExtend(string extend)
        {
            List<byte> indexs;
            if (!ChangeExtend.TryGetValue(extend, out indexs))
            {
                indexs = new List<byte>();
                ChangeExtend.Add(extend, indexs);
            }
        }

        public bool IsChangeField(string field)
        {
            return OldFields.ContainsKey(field);
        }

        public bool IsChangeField(string field, out object old)
        {
            if (OldFields.ContainsKey(field))
            {
                old = OldFields[field];
                return true;
            }

            old = null;
            return false;
        }

        public object GetOldField(string field)
        {
            if (OldFields.ContainsKey(field))
            {
                return OldFields[field];
            }

            return null;
        }

        public object GetNewField(string field)
        {
            if (NewFields.ContainsKey(field))
            {
                return NewFields[field];
            }

            return null;
        }

        public bool IsChangeExtend(string extend, byte index)
        {
            List<byte> indexs;
            if (ChangeExtend.TryGetValue(extend, out indexs))
            {
                // length == 0 全部更新
                if (indexs.Count == 0) return true;
                return indexs.Contains(index);
            }

            return false;
        }

        public bool IsChangeExtend(string extend)
        {
            if (ChangeExtend.ContainsKey(extend)) return true;
            return false;
        }

        public bool IsChangeId(DataType dataType)
        {
            return DependId.Contains(dataType.Value());
        }

        public bool IsChangeNo(DataType dataType)
        {
            return DependNo.Contains(dataType.Value());
        }

        public bool IsChangeOwnNode(DataType dataType)
        {
            return DependNode.Contains(dataType.Value());
        }

        public string ToString()
        {
            var s = "";
            var c = OldFields.GetEnumerator();
            while (c.MoveNext()) s += c.Current.Key + "->" + c.Current.Value;
            c.Dispose();

            s += ":";
            var e = ChangeExtend.GetEnumerator();
            while (e.MoveNext()) s += e.Current.Key + "->" + c.Current.Value;
            e.Dispose();

            s += ":";
            var dId = DependId.GetEnumerator();
            while (dId.MoveNext()) s += dId.Current;
            dId.Dispose();

            s += ":";
            var dNo = DependId.GetEnumerator();
            while (dNo.MoveNext()) s += dNo.Current;
            dNo.Dispose();

            s += ":";
            var dNode = DependNode.GetEnumerator();
            while (dNode.MoveNext()) s += dNode.Current;
            dNode.Dispose();
            return s;
        }

        public void Clear()
        {
            OldFields.Clear();
            NewFields.Clear();
            ChangeExtend.Clear();
            DependId.Clear();
            DependNo.Clear();
            DependNode.Clear();
        }
    }

    public class DataMessage : SubmitData
    {
        public SubmitData Content;
        public byte Event;
        public object[] Params;

        public object Object()
        {
            return new object[]
            {
                Event, Content == null ? new byte[] { } : MessagePackSerializer.Serialize(Content.Object()),
                Params ?? new object[] { }
            };
        }
    }


    public class OperateMessage : SubmitData
    {
        public DefineData Data;
        public DataMessage Message;
        public byte[] Position;

        public object Object()
        {
            return new[] { Data?.Object(), Message.Object(), Position ?? new byte[] { } };
        }
    }

    public class OperateContent : SubmitData
    {
        public CheckData[][] Checks;
        public DefineData From;
        public string Key;
        public string MapNoId;
        public OperateMessage Message;
        public OperateData[] Operates;
        public DefineData Target;

        public object Object()
        {
            return new[]
            {
                Key ?? "", MapNoId ?? "", CheckData.TwoArray(Checks), From?.Object(), Target?.Object(),
                OperateData.Array(Operates), Message?.Object()
            };
        }
    }

    public class TaskContent : SubmitData
    {
        public CheckData[][] Checks;
        public DuplexData Content;
        public DefineData From;
        public byte Task;

        public object Object()
        {
            return new[]
            {
                CheckData.TwoArray(Checks), From != null ? From.Object() : null, Task,
                MessagePackSerializer.Serialize(Content.Object())
            };
        }
    }

    public class ScheduleContent : SubmitData
    {
        public CheckData[][] Checks;
        public SubmitData Content;
        public int Delay;
        public DefineData From;
        public string Key;
        public ScheduleLogic Schedule;
        public DefineData Target;
        public long Time;

        public object Object()
        {
            return new[]
            {
                CheckData.TwoArray(Checks), From != null ? From.Object() : null, Target.Object(), (byte)Schedule, Key,
                Time, MessagePackSerializer.Serialize(Content.Object()), Delay
            };
        }
    }

    public class EventBody : SubmitData
    {
        public List<byte> Current;
        public DefineData Data;

        public object Object()
        {
            return new[] { Data.Object(), Current.ToArray() };
        }

        public static object[] Array(EventBody[] list)
        {
            if (list == null) return new object[] { };
            var s = new object[list.Length];
            for (var i = 0; i < s.Length; i++) s[i] = list[i].Object();

            return s;
        }

        public EventBody AddEvent(byte Event)
        {
            Current.Add(Event);
            return this;
        }
    }

    public class EventContent : SubmitData
    {
        public CheckData[][] Checks;
        public List<byte> Current;
        public List<EventBody> Events;

        public object Object()
        {
            return new object[] { CheckData.TwoArray(Checks), Current.ToArray(), EventBody.Array(Events.ToArray()) };
        }
    }

    public class OnceScheduleContent : SubmitData
    {
        public EventData Event;

        public object Object()
        {
            return new[] { Event.Object() };
        }
    }

    public class RepeatScheduleContent : SubmitData
    {
        public long EndTime;
        public EventData Event;
        public long Repeat;

        public object Object()
        {
            return new[] { Repeat, EndTime, Event.Object() };
        }
    }

    public class RepeatEveryScheduleContent : SubmitData
    {
        public CheckData[][] Checks;
        public DataType DataType;
        public long EndTime;
        public UpdateOperateContent[] Operates;
        public long Repeat;

        public object Object()
        {
            return new object[]
                { CheckData.TwoArray(Checks), Repeat, EndTime, DataType.Value(), UpdateOperateContent.Array(Operates) };
        }
    }

    public class MoveScheduleContent : SubmitData
    {
        public Vector2Int[] Filter;
        public byte Index;
        public Vector2Int LastPosition;
        public SubmitData Logic;
        public bool NoPosition;
        public int OtherMask;
        public Vector2Int[] Plan;
        public byte PlanIndex;
        public Vector2Int[] Positions;
        public int SelfMask;
        public byte Status = 0;
        public TouchScheduleContent Touch;
        public LogicType Type;

        public object Object()
        {
            return new[]
            {
                SerializeInt.Vector2Byte(Plan), PlanIndex, SerializeInt.Vector2Byte(Positions), Index, SelfMask,
                OtherMask, SerializeInt.Vector2Byte(Filter), Status, Type.Value(),
                Logic != null ? MessagePackSerializer.Serialize(Logic.Object()) : new byte[] { },
                NoPosition ? new byte[0] : SerializeInt.Vector2Byte(LastPosition), Touch?.Object()
            };
        }
    }

    public class TouchScheduleContent : SubmitData
    {
        public SubmitData Logic;
        public MoveScheduleContent Move;
        public bool NoPosition;
        public Vector2Int Position;
        public TouchTarget Target;
        public int Times;
        public LogicType Type;

        public object Object()
        {
            return new[]
            {
                Times, NoPosition ? new byte[0] : SerializeInt.Vector2Byte(Position), Type.Value(),
                Logic != null ? MessagePackSerializer.Serialize(Logic.Object()) : new byte[] { }, Target?.Object(),
                Move?.Object()
            };
        }
    }

    public class QueryScheduleContent : SubmitData
    {
        public int AccountId;
        public byte Event;
        public int Identity;
        public object[] Params;

        public object Object()
        {
            return new object[] { AccountId, Identity, Event, Params };
        }
    }

    public class OperateData : SubmitData
    {
        public SubmitData Content;
        public Operate Operate;

        public object Object()
        {
            return new object[] { (byte)Operate, MessagePackSerializer.Serialize(Content.Object()) };
        }

        public static object[] Array(OperateData[] list)
        {
            if (list == null) return new object[] { };
            var s = new object[list.Length];
            for (var i = 0; i < s.Length; i++) s[i] = list[i].Object();

            return s;
        }
    }

    public class DependItem : SubmitData
    {
        public BaseData Depend;
        public string Key;

        public DependItem(string key, BaseData baseData)
        {
            Key = key;
            Depend = baseData;
        }

        public DependItem(object[] objs)
        {
            Key = Convert.ToString(objs[0]);
            Depend = BaseData.Get((object[])objs[1]);
        }

        public object Object()
        {
            return new[] { Key, Depend.Object() };
        }

        public static object[] Array(DependItem[] list)
        {
            if (list == null) return new object[] { };
            var s = new object[list.Length];
            for (var i = 0; i < s.Length; i++) s[i] = list[i].Object();

            return s;
        }
    }

    public class EventItem : SubmitData
    {
        public byte[] Content;
        public byte Event;
        public EventMode Mode;

        public EventItem()
        {
        }

        public EventItem(object[] objs)
        {
            Event = Convert.ToByte(objs[0]);
            Mode = (EventMode)Convert.ToByte(objs[1]);
            Content = (byte[])objs[2];
        }

        public object Object()
        {
            return new object[] { Event, Mode, Content };
        }

        public static object[] Array(EventItem[] list)
        {
            if (list == null) return new object[] { };
            var s = new object[list.Length];
            for (var i = 0; i < s.Length; i++) s[i] = list[i].Object();

            return s;
        }
    }

    public class CreateOperateData : SubmitData
    {
        public CheckBuilder Checks;
        public DefineData Data;
        public Dictionary<string, DependItem> Dependents;
        public EventItem[] Events;
        public string[] ExtendKey;
        public SubmitData Extends;
        public DefineData From;
        public string[] InfoKey;
        public SubmitData Infos;
        public PositionInt Position;

        public object Object()
        {
            var d = new DependItem[Dependents.Count];
            var e = Dependents.GetEnumerator();
            var i = 0;
            while (e.MoveNext())
            {
                d[i] = e.Current.Value;
                i++;
            }

            e.Dispose();
            return new[]
            {
                From?.Object(), Data.Object(), PositionInt.Object(Position), InfoKey, Infos.Object(), ExtendKey,
                Extends?.Object(), DependItem.Array(d), EventItem.Array(Events), CheckData.TwoArray(Checks?.Data())
            };
        }
    }

    public class CreateRelationContent : SubmitData
    {
        public DataType DataType;
        public object Id;

        public object Object()
        {
            return new[] { DataType.Value(), Id };
        }

        public static object[] Array(CreateRelationContent[] list)
        {
            var s = new object[list.Length];
            for (var i = 0; i < s.Length; i++) s[i] = list[i].Object();

            return s;
        }
    }

    public class ResetOperateData : SubmitData
    {
        public CheckBuilder Checks;
        public DefineData Data;
        public Dictionary<string, DependItem> Dependents;
        public EventItem[] Events;
        public DefineData From;
        public string[] InfoKey;
        public SubmitData Infos;
        public string Scene;

        public object Object()
        {
            var d = new DependItem[Dependents.Count];
            var e = Dependents.GetEnumerator();
            var i = 0;
            while (e.MoveNext())
            {
                d[i] = e.Current.Value;
                i++;
            }

            e.Dispose();
            return new[]
            {
                From?.Object(), Data.Object(), InfoKey, Infos?.Object(), DependItem.Array(d), EventItem.Array(Events),
                CheckData.TwoArray(Checks?.Data()), Scene,
            };
        }
    }

    public class UpdateOperateData : SubmitData
    {
        public CheckBuilder Checks;
        public DefineData Data;
        public DefineData From;
        public DataMessage Message;
        public UpdateOperateContent[] Operates;

        public object Object()
        {
            return new[]
            {
                From?.Object(), Data.Object(), UpdateOperateContent.Array(Operates), Message?.Object(),
                CheckData.TwoArray(Checks?.Data())
            };
        }
    }

    public class UpdateOperateContent : SubmitData
    {
        public int Index;
        public string Key = "";
        public UpdateOperate Operate;
        public object Value;

        public object Object()
        {
            return new[] { Key, Index, Value, (byte)Operate };
        }

        public static object[] Array(UpdateOperateContent[] list)
        {
            var s = new object[list.Length];
            for (var i = 0; i < s.Length; i++) s[i] = list[i].Object();

            return s;
        }
    }

    public class DeleteOperateData : SubmitData
    {
        public CheckBuilder Checks;
        public DataType DataType;
        public DefineData From;
        public object Id;

        public object Object()
        {
            return new[] { From?.Object(), DataType.Value(), Id, CheckData.TwoArray(Checks?.Data()) };
        }
    }

    public class EventOperateData : SubmitData
    {
        public byte[] Content;
        public DefineData Data;
        public byte Event;
        public EventMode Mode;

        public object Object()
        {
            return new[] { Data.Object(), Event, Mode, Content };
        }

        public static object[] Array(EventOperateData[] list)
        {
            if (list == null) return new object[] { };
            var s = new object[list.Length];
            for (var i = 0; i < s.Length; i++) s[i] = list[i].Object();

            return s;
        }
    }

    public class CheckData : SubmitData
    {
        public CheckContent[] Checks;
        public BaseData Data;

        public CheckData(DataType dataType, object id)
        {
            Data = new BaseData { DataType = dataType, Id = id };
        }

        public CheckData(object[] objects)
        {
            Data = BaseData.Get((object[])objects[0]);
            var oo = (object[])objects[1];
            Checks = new CheckContent[oo.Length];
            for (var i = 0; i < oo.Length; i++) Checks[i] = new CheckContent((object[])oo[i]);
        }

        public object Object()
        {
            var c = new object[Checks.Length];
            for (var i = 0; i < c.Length; i++) c[i] = Checks[i].Object();
            return new[] { Data.Object(), c };
        }

        public static object[] Array(CheckData[] list)
        {
            if (list == null) return new object[] { };
            var s = new object[list.Length];
            for (var i = 0; i < s.Length; i++) s[i] = list[i].Object();

            return s;
        }

        public static object[] TwoArray(CheckData[][] list)
        {
            if (list == null) return new object[] { };
            var s = new object[list.Length];
            for (var i = 0; i < s.Length; i++) s[i] = Array(list[i]);

            return s;
        }
    }

    public class CheckContent : SubmitData
    {
        public CheckType CheckType;
        public int Index;
        public string Key = "";
        public object Value;

        public CheckContent()
        {
        }

        public CheckContent(object[] objects)
        {
            CheckType = (CheckType)Convert.ToByte(objects[0]);
            Key = Convert.ToString(objects[1]);
            Index = Convert.ToInt32(objects[2]);
            Value = objects[3];
        }

        public object Object()
        {
            return new[] { (byte)CheckType, Key, Index, Value };
        }
    }

    public class EventData : SubmitData
    {
        public SubmitData Content;
        public byte Event;
        public EventMode Mode;

        public object Object()
        {
            return new object[] { (byte)Mode, MessagePackSerializer.Serialize(Content.Object()), Event };
        }

        public static object[] Array(EventData[] list)
        {
            if (list == null) return new object[] { };
            var s = new object[list.Length];
            for (var i = 0; i < s.Length; i++) s[i] = list[i].Object();

            return s;
        }
    }


    public class SortedData : SubmitData
    {
        public int Score;
        public object Value;

        public SortedData(object[] data)
        {
            Value = data[0];
            Score = Convert.ToInt32(data[1]);
        }

        public object Object()
        {
            return new[] { Value, Score };
        }

        public static object[] Array(SortedData[] list)
        {
            if (list == null) return new object[] { };
            var s = new object[list.Length];
            for (var i = 0; i < s.Length; i++) s[i] = list[i].Object();

            return s;
        }
    }

    public class TouchTarget : SubmitData
    {
        public DataType DataType;
        public object Id;

        public object Object()
        {
            return new[] { DataType.Value(), Id };
        }
    }

    public class GOD
    {
        private readonly List<string> _attr = new();

        public GOD(List<string> list)
        {
            _attr = list;
        }

        public GOD(string[] list)
        {
            var l = new List<string>(list);
            _attr = l;
        }

        public int this[string key] => Get(key);

        public string this[int key] => Get(key);


        public int Get(string key)
        {
            return _attr.IndexOf(key);
        }

        public string Get(int key)
        {
            return _attr[key];
        }

        public int[] Dynamic(params string[] key)
        {
            var a = new int[key.Length];
            for (var i = 0; i < key.Length; i++) a[i] = Get(key[i]);

            return a;
        }

        public int[] List(string[] key)
        {
            var a = new int[key.Length];
            for (var i = 0; i < key.Length; i++) a[i] = Get(key[i]);

            return a;
        }

        public object[] Merge(object[] defaultData)
        {
            var a = new object[_attr.Count];
            for (var i = 0; i < _attr.Count; i++) a[i] = new ExtendItem(i, null);

            if (defaultData == null) return a;
            for (var i = 0; i < defaultData.Length; i++) a[i] = defaultData[i];

            return a;
        }

        public ExtendItem[] MergeExtend(object[] defaultData)
        {
            var a = new ExtendItem[_attr.Count];
            for (var i = 0; i < _attr.Count; i++) a[i] = new ExtendItem(i, null);

            if (defaultData == null) return a;
            for (var i = 0; i < defaultData.Length; i++) a[i] = new ExtendItem(i, defaultData[i]);

            return a;
        }
    }
}